﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System8Equations;
using Microsoft.Silverlight.Testing;

namespace t_System8Equations
{
    [TestClass]
    public class t_System8Equations
    {
        [TestMethod]
        public void TestBasicSetup()
        {
            var s = new System8Equations.S8Equations();

            s.n.Total = 300;
            Assert.AreEqual(0.0, s.p.Total, "p shouldn't have changed yet because the efficiencies haven't been set!");

            s.eff_away.eff_b = 0.5;
            Assert.AreEqual(50, s.p.Bottom, "Bottom content on p is incorrect");
            s.eff_away.eff_c = s.eff_away.eff_l = s.eff_away.eff_b;
            Assert.AreEqual(150, s.p.Total, "Total number is not right for p sample");

            Assert.AreEqual(0, s.eff_LT_p.eff_b, "Expected LT_p to be zero before setting anything else!");
            Assert.AreEqual(0, s.eff_SMT_p.eff_b, "Expected SMT_p to be zero before setting anything else!");
            Assert.AreEqual(0, s.eff_LT_n_cl.Value, "Expected the combined guy to be zero before we started out!");

            Assert.AreEqual(0, s.n1.Total, "No tagging eff set - so n1 sample should be zero");
            s.eff_LT_n.eff_b = s.eff_LT_n.eff_c = s.eff_LT_n.eff_l = 0.5;
            Assert.AreEqual(150, s.n1.Total, "With tagging at 50% expected somethign in the n1 sample!");

            Assert.AreEqual(0, s.n2.Total, "No tagging eff set - so n2 sample should be zero");
            s.eff_SMT_n.eff_b = s.eff_SMT_n.eff_c = s.eff_SMT_n.eff_l = 0.5;
            Assert.AreEqual(150, s.n2.Total, "With tagging at 50% expected somethign in the n2 sample!");

            s.eff_LT_p.eff_b = 0.25;
            Assert.AreEqual(0.5, s.alpha_LT_p_n.alpha_b, "alpha lt p_n doesn't seem to be hooked up correctly");
            s.eff_LT_p.eff_b = 0.5;
            Assert.AreEqual(1.0, s.alpha_LT_p_n.alpha_b, "alpha lt p_n doesn't seem to be hooked up correctly after resetting to what should be one");
            s.eff_LT_p.eff_c = s.eff_LT_p.eff_l = s.eff_LT_p.eff_b;

            Assert.AreEqual(75, s.p1.Total, "With tagging at 50% expected somethign in the p1 sample!");
            s.eff_SMT_p.eff_b = s.eff_SMT_p.eff_c = s.eff_SMT_p.eff_l = 0.5;
            Assert.AreEqual(75, s.p2.Total, "With tagging at 50% expected somethign in the p2 sample!");
        }

        [TestMethod]
        public void TestBasicEffCL()
        {
            var s = new System8Equations.S8Equations();

            s.n.Charm = 100;
            s.n1.Charm = 50;
            Assert.AreEqual(0.5, s.eff_LT_n_cl.Value, "Lt n cl is not correct");

            s.p.Charm = 100;
            s.p1.Charm = 50;
            Assert.AreEqual(0.5, s.eff_LT_p_cl.Value, "Lt p cl is not correct");

            Assert.AreEqual(1.0, s.eff_away_cl.Value, "away cl is not correct");

            s.n2.Charm = 60;
            Assert.AreEqual(0.6, s.eff_SMT_n_cl.Value, "smt n cl is not correct");

            s.p2.Charm = 60;
            Assert.AreEqual(0.6, s.eff_SMT_p_cl.Value, "smt p cl is not correct");

            s.n.Charm = 100;
            Assert.AreEqual(s.n12.Charm / 100.0, s.eff_SMTLT_n_cl.Value, "smtlt n cl is not correct");
            s.p.Charm = 100;
            Assert.AreEqual(s.p12.Charm / 100.0, s.eff_SMTLT_p_cl.Value, "smtlt p cl is not correct");
        }

        [TestMethod]
        public void TestAlphaCLs()
        {
            var s = new System8Equations.S8Equations();

            s.n.Charm = 100;
            s.n1.Charm = 50;
            s.p.Charm = 100;
            s.p1.Charm = 25.0;
            Assert.AreEqual(0.5, s.alpha_LT_p_n.alpha_c, "Expected alpha_c to be set now");
            Assert.AreEqual(0.5, s.alpha_LT_p_n_cl.Value, "alpha lt p n cl is not correct");


            s.n2.Charm = 60;
            s.p2.Charm = 30;
            s.alpha_SMT_p_n.alpha_c = 2.0;
            Assert.AreEqual(0.5, s.alpha_SMT_p_n_cl.Value, "smt p n cl is not correct");
        }

        [TestMethod]
        public void TestSequentialSetting()
        {
            var s = new System8Equations.S8Equations();
            s.n.Total = 497008;
            Assert.AreEqual(497008, s.n.Total, "n not sticking!");
            s.p.Total = 26790;
            Assert.AreEqual(26790, s.p.Total, "p not sticking!");
            s.n1.Total = 60463;
            Assert.AreEqual(60463, s.n1.Total, "n1 not sticking!");
            s.p1.Total = 7159;
            Assert.IsTrue(CloseTo(7159, s.p1.Total), "p1 not sticking!");
            s.n2.Total = 213012;
            Assert.AreEqual(213012, s.n2.Total, "n2 not sticking!");
            s.p2.Total = 16886;
            Assert.AreEqual(16886, s.p2.Total, "p2 not sticking!");
            s.n12.Total = 36807;
            Assert.IsTrue(CloseTo(36807, s.n12.Total), "n12 not sticking!");
            s.p12.Total = 5130;
            Assert.IsTrue(CloseTo(5130, s.p12.Total), "p12 not sticking!");

            Assert.AreEqual(497008, s.n.Total, "n didn't sticking!");
            Assert.AreEqual(26790, s.p.Total, "p didn't sticking!");
            Assert.AreEqual(60463, s.n1.Total, "n1 didn't sticking!");
            Assert.AreEqual(7159, s.p1.Total, "p1 didn't sticking!");
            Assert.AreEqual(213012, s.n2.Total, "n2 didn't sticking!");
            Assert.AreEqual(16886, s.p2.Total, "p2 didn't sticking!");
            Assert.AreEqual(36807, s.n12.Total, "n12 didn't sticking!");
            Assert.AreEqual(5130, s.p12.Total, "p12 didn't sticking!");
        }

        private bool CloseTo(double p, double p2)
        {
            double delta = Math.Abs(p - p2) / p;
            return delta < 0.001;
        }

        [TestMethod]
        public void TestDoubleTagAlphas()
        {
            var s = new System8Equations.S8Equations();
            s.n.Bottom = 1000;
            s.n.Charm = 1000;

            s.p.Bottom = 500;
            s.p.Charm = 500;

            s.n1.Bottom = 500;
            s.n1.Charm = 500;

            s.p1.Bottom = 250;
            s.p1.Charm = 250;

            s.n2.Bottom = 500;
            s.n2.Charm = 500;

            s.p2.Bottom = 250;
            s.p2.Charm = 250;

            s.n12.Bottom = 250;
            s.n12.Charm = 250;

            s.p12.Bottom = 250 / 2.0;
            s.p12.Charm = 250 / 2.0;

            ///
            /// Do the straight up alpha's
            /// 

            Assert.AreEqual(1.0, s.alpha_SMTLT_n.alpha_b, "Expected a unity n alpha for smt lt n");
            Assert.AreEqual(1.0, s.alpha_SMTLT_n.alpha_c, "Expected a unity n alpha for smt lt c");

            Assert.AreEqual(1.0, s.alpha_SMTLT_p.alpha_b, "Expected a unity p alpha for smt lt n");
            Assert.AreEqual(1.0, s.alpha_SMTLT_p.alpha_c, "Expected a unity p alpha for smt lt c");

            ///
            /// Next, do the cl's, which are a bit more complex.
            /// 

            Assert.AreEqual(1.0, s.alpha_SMTLT_n_cl.Value, "Expected a unity n alpha for smt lt cl");
            Assert.AreEqual(1.0, s.alpha_SMTLT_p_cl.Value, "Expected a unity p alpha for smt lt cl");

            ///
            /// Try something a little off. Make sure it doesn't affect the others too.
            /// 

            s.n.Bottom = 1000;
            s.n1.Bottom = 600;
            s.n2.Bottom = 600;
            s.n12.Bottom = 400;

            Assert.IsTrue(CloseTo(10.0 / 9.0, s.alpha_SMTLT_n.alpha_b), "Expected a non-one alpha!");

            Assert.AreEqual(1.0, s.alpha_SMTLT_p.alpha_b, "Expected a unity p alpha for smt lt n");
            Assert.AreEqual(1.0, s.alpha_SMTLT_p.alpha_c, "Expected a unity p alpha for smt lt c");
            Assert.AreEqual(1.0, s.alpha_SMTLT_p_cl.Value, "Expected a unity p alpha for smt lt cl");

            ///
            /// And make sure the cl guys are set right too!
            /// 

            s.n.Charm = 1000;
            s.n1.Charm = 600;
            s.n2.Charm = 600;
            s.n12.Charm = 400;
            Assert.IsTrue(CloseTo(10.0 / 9.0, s.alpha_SMTLT_n_cl.Value), "Expected a non-one alpha!");
            Assert.AreEqual(1.0, s.alpha_SMTLT_p_cl.Value, "Expected a unity p alpha for smt lt cl");
        }

        [TestMethod]
        public void TestCopy()
        {
            System8Equations.S8Equations eqn = new System8Equations.S8Equations();
            System8Equations.S8Equations s2 = new System8Equations.S8Equations();

            NiceS8(eqn);

            s2.Copy(eqn);

            Assert.AreEqual(10000, s2.n.Bottom, "n.bottom");
            Assert.AreEqual(10000, s2.n.Charm, "n.Charm");
            Assert.AreEqual(10000, s2.n.Light, "n.Light");

            Assert.AreEqual(5000, s2.n1.Bottom, "n1.bottom");
            Assert.AreEqual(5000, s2.n1.Charm, "n1.Charm");
            Assert.AreEqual(5000, s2.n1.Light, "n1.Light");

            Assert.AreEqual(5000, s2.n2.Bottom, "n2.bottom");
            Assert.AreEqual(5000, s2.n2.Charm, "n2.Charm");
            Assert.AreEqual(5000, s2.n2.Light, "n2.Light");

            Assert.AreEqual(2500, s2.n12.Bottom, "n12.bottom");
            Assert.AreEqual(2500, s2.n12.Charm, "n12.Charm");
            Assert.AreEqual(2500, s2.n12.Light, "n12.Light");

            Assert.AreEqual(10000, s2.p.Bottom, "p.bottom");
            Assert.AreEqual(10000, s2.p.Charm, "p.Charm");
            Assert.AreEqual(10000, s2.p.Light, "p.Light");

            Assert.AreEqual(5000, s2.p1.Bottom, "p1.bottom");
            Assert.AreEqual(5000, s2.p1.Charm, "p1.Charm");
            Assert.AreEqual(5000, s2.p1.Light, "p1.Light");

            Assert.AreEqual(5000, s2.p2.Bottom, "p2.bottom");
            Assert.AreEqual(5000, s2.p2.Charm, "p2.Charm");
            Assert.AreEqual(5000, s2.p2.Light, "p2.Light");

            Assert.AreEqual(2500, s2.p12.Bottom, "p12.bottom");
            Assert.AreEqual(2500, s2.p12.Charm, "p12.Charm");
            Assert.AreEqual(2500, s2.p12.Light, "p12.Light");
        }

        /// <summary>
        /// Setup something "nice".
        /// </summary>
        /// <param name="eqn"></param>
        private static void NiceS8(System8Equations.S8Equations eqn)
        {
            eqn.n.Bottom = 10000;
            eqn.n.Charm = 10000;
            eqn.n.Light = 10000;

            eqn.n1.Bottom = 5000;
            eqn.n1.Charm = 5000;
            eqn.n1.Light = 5000;

            eqn.n2.Bottom = 5000;
            eqn.n2.Charm = 5000;
            eqn.n2.Light = 5000;

            eqn.n12.Bottom = 2500;
            eqn.n12.Charm = 2500;
            eqn.n12.Light = 2500;

            eqn.p.Bottom = 10000;
            eqn.p.Charm = 10000;
            eqn.p.Light = 10000;

            eqn.p1.Bottom = 5000;
            eqn.p1.Charm = 5000;
            eqn.p1.Light = 5000;

            eqn.p2.Bottom = 5000;
            eqn.p2.Charm = 5000;
            eqn.p2.Light = 5000;

            eqn.p12.Bottom = 2500;
            eqn.p12.Charm = 2500;
            eqn.p12.Light = 2500;
        }

        [TestMethod]
        public void TestUpdateEvent()
        {
            System8Equations.S8Equations eqn = new System8Equations.S8Equations();
            NiceS8(eqn);

            int count = 0;
            eqn.ValuesUpdated += new Action(() => count++);

            Assert.AreEqual(0, count, "Count shouldn't get updated yet!");

            eqn.n.Total = 20000;
            Assert.AreEqual(1, count, "Even though there were lots of changes, there should have been only a single one logged");
        }
    }
}